/*
 * BatteryStatus.cpp
 *
 *  Created on: 2012-3-31
 *      Author: kylin
 */

#include "BatteryStatus.h"
#include "rs485.h"
#include "PanelLed.h"
#include "gdata.h"

BatteryStatus gbattery;

#define REPORT_PORT 222

const quint32 voltage_CapTooLow=13;
const quint32 capFull=20000;
const quint32 voltage_CapFull=16;

const quint32 voltage_min=12000;
const quint32 voltage_max=18000;
const quint32 voltage_single_min=1000;
const quint32 voltage_single_max=1500;
const qint32 current_charge_max=1200;
const qint32 current_discharge_max=6000;
const quint32 temp_max=700;

//////////////////////////////////////////////////////////////////////
// class BatteryQueryThread
BatteryQueryThread::BatteryQueryThread(const QString& devNode,
		KjDeviceList* lstDevice,QObject* parent)
	: kthread(parent),m_devNode(devNode),m_lstDevice(lstDevice)
{
	gbattery.powerAC1=0;
	gbattery.powerAC2=0;

}

BatteryQueryThread::~BatteryQueryThread()
{

}

const quint8 bit_test8[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
const quint16 bit_test16[]={0x0001,0x0002,0x0004,0x0008,
						   0x0010,0x0020,0x0040,0x0080,
						   0x0100,0x0200,0x0400,0x0800,
						   0x1000,0x2000,0x4000,0x8000};

void BatteryQueryThread::run()
{
	char buf[128];
	char sendBuf[128];
	char* pdata;
	quint16 lrc,lrcCalc;
	quint16 current;
	quint16 alarmTemp;
	BatEvent event;
	quint8 alarmIndex;
	quint8 coffLockCount=0;
	bool bwarn=false;

	rs485* port=new rs485(m_devNode);

	if(!port->init())
	{
		delete port;
		setStarted(false);
		return;
	}

	setStarted(true);

	while(true)
	{
		if(needExit())
			break;

		if(port->recv(buf,76,500))
		{
			if((buf[0]==0x3A)&&
					(buf[1]==0xFF))
			{
				msleep(10);

				sendBuf[0]=0x3A;
				sendBuf[1]=0xFF;
				pdata=sendBuf+2;
				if(gbattery.chnnlCofWrite)
				{
					gbattery.chnnlCofWrite=0;
					*(pdata++)=0x01;
//					qWarning()<<"Write chnnl coff";
				}
				else
					*(pdata++)=0x00;

				for(int i=0;i<gbattery.lstChnnlCof.size();i++)
				{
					*(pdata++)=U16_LO8(gbattery.lstChnnlCof[i]);
					*(pdata++)=U16_HI8(gbattery.lstChnnlCof[i]);
				}

				*(pdata++)=0x00;
				*(pdata++)=0x00;
				*(pdata++)=0x00;
				*(pdata++)=0x00;
				*(pdata++)=0x00;

				lrc=0;
				for(int i=0;i<pdata-sendBuf;i++)
					lrc+=sendBuf[i];

				*(pdata++)=U16_LO8(lrc);
				*(pdata++)=U16_HI8(lrc);
				*(pdata++)=0x0D;
				*(pdata++)=0x0A;

//				if(sendBuf[2])
					port->send(sendBuf,pdata-sendBuf);
				bwarn=false;
				lrc=buf[73]*0x100+buf[72];
				lrcCalc=0;
				for(int i=0;i<72;i++)
					lrcCalc+=buf[i];

				if(lrcCalc!=lrc)
				{
					qWarning()<<"Battery recv crc error";
					continue;
				}

//				if(lrc==lrcCalc)
				{
					gbattery.lock.lock();
					event.timeOccur=QDateTime::currentDateTime().toTime_t();
					current=U8_TO_U16(buf[4],buf[3]);
					if(current&0x8000)
						gbattery.current=current&0x7FFF;
					else
						gbattery.current=-current;

					gbattery.tempAvg=U8_TO_U16(buf[6],buf[5])-500;
					gbattery.volMol1=U8_TO_U16(buf[8],buf[7]);
					gbattery.volMol2=U8_TO_U16(buf[10],buf[9]);
					gbattery.volMol3=U8_TO_U16(buf[12],buf[11]);
					gbattery.volMol4=U8_TO_U16(buf[14],buf[13]);
					gbattery.volMol5=U8_TO_U16(buf[16],buf[15]);
					gbattery.volMol6=U8_TO_U16(buf[18],buf[17]);
					gbattery.volMol7=U8_TO_U16(buf[20],buf[19]);
					gbattery.volMol8=U8_TO_U16(buf[22],buf[21]);
					gbattery.volMol9=U8_TO_U16(buf[24],buf[23]);
					gbattery.volMol10=U8_TO_U16(buf[26],buf[25]);
					gbattery.volMol11=U8_TO_U16(buf[28],buf[27]);
					gbattery.volMol12=U8_TO_U16(buf[30],buf[29]);
					if(gbattery.volMol12&0x8000)
					{
						gbattery.volMol12=U8_TO_U16(buf[30],buf[29]);
					}
					gbattery.capRemain=U8_TO_U16(buf[64],buf[63]);

					if(gbattery.chnnlCofWrite)
					{
						coffLockCount++;
						if(coffLockCount>10)
						{
							coffLockCount=0;
							gbattery.chnnlCofWrite=0;
						}
					}
					else
					{
						for(int i=0;i<gbattery.lstChnnlCof.size();i++)
						{
							gbattery.lstChnnlCof[i]=U8_TO_U16(buf[32+i*2],
									buf[31+2*i]);
						}
					}

					gbattery.powerAC1=!(buf[65]&0x01);
					gbattery.powerAC2=!(buf[65]&0x02);

					gbattery.voltage=gbattery.volMol1+
							gbattery.volMol2+
							gbattery.volMol3+
							gbattery.volMol4+
							gbattery.volMol5+
							gbattery.volMol6+
							gbattery.volMol7+
							gbattery.volMol8+
							gbattery.volMol9+
							gbattery.volMol10+
							gbattery.volMol11+
							gbattery.volMol12;

					if((qint32)(gbattery.voltage)<0)
					{
						qWarning()<<"Invalid battery voltage";
					}

					// Write measure value to device
					m_lstDevice->writePointValue(BAT_CPU_NUM,pvtAi,
							1,gbattery.voltage);
					m_lstDevice->writePointValue(BAT_CPU_NUM,pvtAi,
							2,gbattery.current);
					m_lstDevice->writePointValue(BAT_CPU_NUM,pvtAi,
							3,gbattery.tempAvg);
					m_lstDevice->writePointValue(BAT_CPU_NUM,pvtAi,
							4,gbattery.capRemain);
					m_lstDevice->writePointValue(BAT_CPU_NUM,pvtAi,
							5,gbattery.volMol1);
					m_lstDevice->writePointValue(BAT_CPU_NUM,pvtAi,
							6,gbattery.volMol2);
					m_lstDevice->writePointValue(BAT_CPU_NUM,pvtAi,
							7,gbattery.volMol3);
					m_lstDevice->writePointValue(BAT_CPU_NUM,pvtAi,
							8,gbattery.volMol4);
					m_lstDevice->writePointValue(BAT_CPU_NUM,pvtAi,
							9,gbattery.volMol5);
					m_lstDevice->writePointValue(BAT_CPU_NUM,pvtAi,
							10,gbattery.volMol6);
					m_lstDevice->writePointValue(BAT_CPU_NUM,pvtAi,
							11,gbattery.volMol7);
					m_lstDevice->writePointValue(BAT_CPU_NUM,pvtAi,
							12,gbattery.volMol8);
					m_lstDevice->writePointValue(BAT_CPU_NUM,pvtAi,
							13,gbattery.volMol9);
					m_lstDevice->writePointValue(BAT_CPU_NUM,pvtAi,
							14,gbattery.volMol10);
					m_lstDevice->writePointValue(BAT_CPU_NUM,pvtAi,
							15,gbattery.volMol11);
					m_lstDevice->writePointValue(BAT_CPU_NUM,pvtAi,
							16,gbattery.volMol12);

					// set alarm status
					alarmTemp=U8_TO_U16(buf[67],buf[66]);
					for(int i=0;i<13;i++)
					{
						alarmIndex=i;
						if(alarmTemp&bit_test16[i])
						{
							if(!gbattery.lstDiValue[alarmIndex])
							{
								if(m_lstDevice->putEvent(BAT_CPU_NUM,
										ketSoe,alarmIndex+1,
										QDateTime::currentDateTime().toTime_t(),
										QByteArray().append(1)))
								{
									gbattery.lstDiValue[alarmIndex]=1;
								}
								bwarn=true;
							}
						}
						else
						{
							if(gbattery.lstDiValue[alarmIndex])
							{
								if(m_lstDevice->putEvent(BAT_CPU_NUM,
										ketSoe,alarmIndex+1,
										QDateTime::currentDateTime().toTime_t(),
										QByteArray().append((char)0)))
								{
									gbattery.lstDiValue[alarmIndex]=0;
								}
							}
						}
					}

					alarmTemp=U8_TO_U16(buf[69],buf[68]);
					for(int i=0;i<13;i++)
					{
						alarmIndex=i+13;
						if(alarmTemp&bit_test16[i])
						{
							if(!gbattery.lstDiValue[alarmIndex])
							{
								if(m_lstDevice->putEvent(BAT_CPU_NUM,
										ketSoe,alarmIndex+1,
										QDateTime::currentDateTime().toTime_t(),
										QByteArray().append(1)))
								{
									gbattery.lstDiValue[alarmIndex]=1;
								}
								bwarn=true;
							}
						}
						else
						{
							if(gbattery.lstDiValue[alarmIndex])
							{
								if(m_lstDevice->putEvent(BAT_CPU_NUM,
										ketSoe,alarmIndex+1,
										QDateTime::currentDateTime().toTime_t(),
										QByteArray().append((char)0)))
								{
									gbattery.lstDiValue[alarmIndex]=0;
								}
							}
						}
					}

					alarmTemp=U8_TO_U16(0,buf[70]);
					for(int i=0;i<4;i++)
					{
						alarmIndex=i+26;
						if(alarmTemp&bit_test16[i])
						{
							if(!gbattery.lstDiValue[alarmIndex])
							{
								if(m_lstDevice->putEvent(BAT_CPU_NUM,
										ketSoe,alarmIndex+1,
										QDateTime::currentDateTime().toTime_t(),
										QByteArray().append(1)))
								{
									gbattery.lstDiValue[alarmIndex]=1;
								}
								bwarn=true;
							}
						}
						else
						{
							if(gbattery.lstDiValue[alarmIndex])
							{
								if(m_lstDevice->putEvent(BAT_CPU_NUM,
										ketSoe,alarmIndex+1,
										QDateTime::currentDateTime().toTime_t(),
										QByteArray().append((char)0)))
								{
									gbattery.lstDiValue[alarmIndex]=0;
								}
							}
						}
					}

					if(bwarn)
					{
						gled->flashLed(led_DC,0xFFFFFFFF);
					}
					else
					{
						gled->turnOffLed(led_DC);
					}
					if(gbattery.powerAC1)
					{
						gled->flashLed(led_AC1,0xFFFFFFFF);
					}
					else
					{
						gled->turnOffLed(led_AC1);
					}
					if(gbattery.powerAC2)
					{
						gled->flashLed(led_AC2,0xFFFFFFFF);
					}
					else
					{
						gled->turnOffLed(led_AC2);
					}
					gbattery.lock.unlock();

				}
			}
			else
			{
				continue;
			}
		}
	}
	delete port;
	setStarted(false);
}

//////////////////////////////////////////////////////////////////////
// class BatteryStatusQuery
BatteryStatusQuery::BatteryStatusQuery(quint32 id,const QString& devNode,
		KjDeviceList* lstDevice)
	: DeviceProtocol(id,devNode,lstDevice)
{

}

BatteryStatusQuery::~BatteryStatusQuery()
{

}

bool BatteryStatusQuery::start()
{
	m_processor=new BatteryQueryThread(m_devNode,m_lstDevice);

	return m_processor->start(5000);
}

void BatteryStatusQuery::stop()
{
	m_processor->exit();
	m_processor->wait(5000);
	delete m_processor;
}
